home *** CD-ROM | disk | FTP | other *** search
/ The X-Philes (2nd Revision) / The X-Philes Number 1 (1995).iso / xphiles / hp95 / freyja13.exe / lha / DATE.C < prev    next >
C/C++ Source or Header  |  1992-03-22  |  9KB  |  418 lines

  1. /* DATE.C -- Calendar Routines
  2.  
  3.     Written June 1991 by Craig A. Finseth
  4.     Copyright 1991 by Craig A. Finseth
  5. */
  6.  
  7. #include "freyja.h"
  8. #if defined(MSDOS)
  9. #include <time.h>
  10. time_t time();
  11. struct tm *localtime();
  12. #endif
  13.  
  14. #define SYS_CAL        "%cal%"
  15. #define CAL_WIDTH    35
  16.  
  17.     /* Cumulative month start day number.  Yes, I know this has 13
  18.     months. */
  19. static int mdays[] = {
  20.     0,
  21.     0 + 31,
  22.     0 + 31 + 28,
  23.     0 + 31 + 28 + 31,
  24.     0 + 31 + 28 + 31 + 30,
  25.     0 + 31 + 28 + 31 + 30 + 31,
  26.     0 + 31 + 28 + 31 + 30 + 31 + 30,
  27.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31,
  28.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  29.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  30.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  31.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
  32.     0 + 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31 };
  33.  
  34. char *daynames[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "" };
  35. char *monthnames[] = { "January", "Febuary", "March", "April", "May", "June",
  36.     "July", "August", "September", "October", "November", "December" };
  37.  
  38. static FLAG initted = FALSE;    /* for current calendar */
  39. static int cal_month;
  40. static int cal_year;
  41.  
  42. static int cal_start = 0;    /* starting day of week, 0 = Sunday */
  43.  
  44. void D_Calendar();        /* void */
  45. void D_MakeConsistent();    /* int *yearptr, int *monptr */
  46.  
  47. /* ------------------------------------------------------------ */
  48.  
  49. /* Create and insert a calendar. */
  50.  
  51. void
  52. DCal()
  53.     {
  54.     struct tm t;
  55.  
  56.     if (!initted) {
  57.         initted = TRUE;
  58.         DNow(&t);
  59.         cal_month = t.tm_mon;
  60.         cal_year = t.tm_year;
  61.         }
  62.     if (!isuarg) ;
  63.     else if (uarg < 100) {
  64.         cal_month = uarg;
  65.         }
  66.     else if (uarg < 10000) {
  67.         cal_year = uarg;
  68.         }
  69.     else    {
  70.         cal_year = uarg % 10000;
  71.         cal_month = uarg / - 1;
  72.         }
  73.     D_MakeConsistent(&cal_year, &cal_month);
  74.     D_Calendar();
  75.     uarg = 0;
  76.     }
  77.  
  78.  
  79. /* ------------------------------------------------------------ */
  80.  
  81. /* Change the calendar by NUM months. */
  82.  
  83. void
  84. DMove(num)
  85.     int num;
  86.     {
  87.     struct tm t;
  88.  
  89.     if (!initted) {
  90.         initted = TRUE;
  91.         DNow(&t);
  92.         cal_month = t.tm_mon;
  93.         cal_year = t.tm_year;
  94.         }
  95.     cal_month += num;
  96.     D_MakeConsistent(&cal_year, &cal_month);
  97.     D_Calendar();
  98.     }
  99.  
  100.  
  101. /* ------------------------------------------------------------ */
  102.  
  103. /* Advance the calendar by UARG months. */
  104.  
  105. void
  106. DNext()
  107.     {
  108.     if (!isuarg) uarg = 1;
  109.     DMove(uarg);
  110.     uarg = 0;
  111.     }
  112.  
  113.  
  114. /* ------------------------------------------------------------ */
  115.  
  116. /* Return the current date and time in TPTR. */
  117.  
  118. void
  119. DNow(tptr)
  120.     struct tm *tptr;
  121.     {
  122.     time_t now;
  123.  
  124. #if defined(SYSMGR)
  125.     JGetDate(&tptr->tm_year, &tptr->tm_mon, &tptr->tm_mday);
  126. #else
  127.     now = time(NULL);
  128.     *tptr = *localtime(&now);
  129.     tptr->tm_year += 1900;
  130. #endif
  131.     }
  132.  
  133.  
  134. /* ------------------------------------------------------------ */
  135.  
  136. /* Return the day of the week (0 = Sunday) for the supplied day number. */
  137.  
  138. int
  139. DOW(day)
  140.     long day;
  141.     {
  142.     return((day + 0) % 7);
  143.     }
  144.  
  145.  
  146. /* ------------------------------------------------------------ */
  147.  
  148. /* Rewind the calendar by UARG months. */
  149.  
  150. void
  151. DPrev()
  152.     {
  153.     if (!isuarg) uarg = 1;
  154.     DMove(-uarg);
  155.     uarg = 0;
  156.     }
  157.  
  158.  
  159. /* ------------------------------------------------------------ */
  160.  
  161. /* Setup the day of week start (0=sunday). */
  162.  
  163. void
  164. DSetup(weekstart)
  165.     int weekstart;
  166.     {
  167.     cal_start = weekstart;
  168.     }
  169.  
  170.  
  171. /* ------------------------------------------------------------ */
  172.  
  173. /* Convert the day number to a date.  CAL is 0=360 day, 2=365 day,
  174. other=actual.  Should do sanity checking, but... */
  175.  
  176. void
  177. DToDate(tptr, day, cal)
  178.     struct tm *tptr;
  179.     long day;
  180.     int cal;
  181.     {
  182.     long dn;
  183.     long ltmp;
  184.  
  185.     memset((char *)tptr, NUL, sizeof(*tptr));
  186.  
  187.     switch (cal) {
  188.  
  189.     case 0:
  190.         tptr->tm_year = day / 360;
  191.         tptr->tm_mon = (day % 360) / 30;
  192.         tptr->tm_mday = (day % 30) + 1;
  193.         break;
  194.  
  195.     case 2:
  196.         tptr->tm_year = day / 365;
  197.         day %= 365;
  198.         for (tptr->tm_mon = 0;
  199.             day >= mdays[tptr->tm_mon + 1];
  200.             tptr->tm_mon++) ;
  201.         tptr->tm_mday = day - mdays[tptr->tm_mon] + 1;
  202.         break;
  203.  
  204.     default:
  205. /* Divide the day number by 365.2422 to get real close to the correct
  206. year.  We must do this with ints, so multiply by 10,000 and divide by
  207. 3652422.  But our day numbers range up to 9999 * 366 (or so) =
  208. 3,600,000.  Multiplying by 10,000 exceeds a 32-bit int.  We have to
  209. reduce the 10,000 by a factor of 20 or so in order not to overflow.
  210.  
  211. If we call the orgininal number 365.2425 and so get 10,000 and
  212. 3652425, we can remove a factor of 25 and obain 400 and 146,097.  This
  213. works but is incorrect to the tune of 3 parts in (roughly) 3,000,000
  214. or 1 in 1,000,000.  As there are only about 2,500 leap year days that
  215. can foul things up, we are still close enough.  Later steps will
  216. correct any error. */
  217.  
  218.         ltmp = day * 400;
  219.         ltmp /= 146097;
  220.  
  221. /* Now the corrections start.  First, make sure that we are before the
  222. correct year. */
  223.  
  224.         tptr->tm_year = ltmp - 2;
  225.  
  226. /* Now, count up until we get to the correct year. */
  227.  
  228.         tptr->tm_mon = 0;
  229.         tptr->tm_mday = 1;
  230.         for (dn = 0; dn < day; tptr->tm_year++) {
  231.             dn = DToDayN(tptr, 1);
  232.             if (dn == day) return;    /* done! */
  233.             }
  234.         tptr->tm_year -= 2;
  235.  
  236. /* We now have the correct year. On to the month and day. */
  237.  
  238.         day -= DToDayN(tptr, 1);
  239.  
  240.         if (day < mdays[1]) {
  241.             tptr->tm_mday = day + 1;    /* Jan */
  242.             return;
  243.             }
  244.         else if (day < mdays[2]) {
  245.             tptr->tm_mon = 1;
  246.             tptr->tm_mday = day - mdays[1] + 1; /* Feb 28 */
  247.             return;
  248.             }
  249.  
  250. /* It is either Feb 29 (if we have a leap year), or some day after that */
  251.  
  252. /* See if we are a leap year. */
  253.         if (tptr->tm_year / 4 == 0 &&
  254.             (tptr->tm_year / 100 != 0 ||
  255.              tptr->tm_year / 400 == 0)) {    /* leap year */
  256.             if (day == mdays[2]) {
  257.                 tptr->tm_mon = 1;
  258.                 tptr->tm_mday = 29;
  259.                 return;
  260.                 }
  261.             day--;        /* treat as regular day */
  262.             }
  263.  
  264.         for (tptr->tm_mon = 2;
  265.             day >= mdays[tptr->tm_mon + 1];
  266.             tptr->tm_mon++) ;
  267.         tptr->tm_mday = day - mdays[tptr->tm_mon] + 1;
  268.         break;
  269.         }
  270.     }
  271.  
  272.  
  273. /* ------------------------------------------------------------ */
  274.  
  275. /* Convert the date to a day number and return the day number.  CAL is
  276. 0=360 day, 2=365 day, other=actual. */
  277.  
  278. long
  279. DToDayN(tptr, cal)
  280.     struct tm *tptr;
  281.     int cal;
  282.     {
  283.     long tmp;
  284.     int y;
  285.     int m;
  286.     int d;
  287.  
  288.     y = tptr->tm_year;
  289.     m = tptr->tm_mon;
  290.     d = tptr->tm_mday;
  291.  
  292.     D_MakeConsistent(&y, &m);
  293.     if (d < 1 || d > 31) d = 1;
  294.  
  295.     switch (cal) {
  296.  
  297.     case 0:
  298.         tmp = (360 * (long)y) + 30 * m + d - 1;
  299.         break;
  300.  
  301.     case 2:
  302.         tmp = (365 * (long)y) + mdays[m] + d - 1;
  303.         break;
  304.  
  305.     default:
  306.         tmp = (365 * (long)y) + mdays[m] + d - 1;
  307.  
  308.             /* Jan and Feb get previous year's leap year counts */
  309.         if (m <= 1) y--;
  310.  
  311.         tmp += y / 4;        /* add leap years */
  312.         tmp -= y / 100;        /* subtract non-leap cents. */
  313.         tmp += y / 400;        /* add back 400 years */
  314.         break;
  315.         }
  316.     return(tmp);
  317.     }
  318.  
  319.  
  320. /* ------------------------------------------------------------ */
  321.  
  322. /* Display a calendar, given a date. */
  323.  
  324. #if !defined(NOCALC)
  325. void
  326. DXCal(tptr)
  327.     struct tm *tptr;
  328.     {
  329.     initted = TRUE;
  330.  
  331.     cal_month = tptr->tm_mon;
  332.     cal_year = tptr->tm_year;
  333.  
  334.     D_MakeConsistent(&cal_year, &cal_month);
  335.     D_Calendar();
  336.     }
  337. #endif
  338.  
  339.     
  340. /* ------------------------------------------------------------ */
  341.  
  342. /* Display the calendar. */
  343.  
  344. void
  345. D_Calendar()
  346.     {
  347.     struct tm t;
  348.     char buf[LINEBUFFSIZE];
  349.     int cnt;
  350.     int start;
  351.     int numdays;
  352.     long dayn;
  353.  
  354.     if (!FMakeSys(SYS_CAL, TRUE)) return;
  355.  
  356.     xsprintf(buf, "%s %4d\n", monthnames[cal_month], cal_year);
  357.     BInsSpaces((CAL_WIDTH - strlen(buf) - 1) / 2);
  358.     BInsStr(buf);
  359.  
  360.     for (cnt = 0; cnt < 7; cnt++) {
  361.         xsprintf(buf, " %s ", daynames[(cnt + cal_start) % 7]);
  362.         BInsStr(buf);
  363.         }
  364.     BInsChar(NL);
  365.  
  366.     t.tm_year = cal_year;
  367.     t.tm_mon = cal_month;
  368.     t.tm_mday = 1;
  369.     dayn = DToDayN(&t, 1);
  370.     start = DOW(dayn);
  371.  
  372.     t.tm_mon++;
  373.     numdays = DToDayN(&t, 1) - dayn;
  374.  
  375.     BInsSpaces(5 * start);
  376.     for (cnt = 1; cnt < numdays + 1; cnt++) {
  377.         xsprintf(buf, "  %2d%c", cnt,
  378.             (cnt + start + cal_start) % 7  == 0 ? NL : SP);
  379.         BInsStr(buf);
  380.         }
  381.     BMoveBy(-1);
  382.     BCharDelete(1);
  383.     BInsChar(NL);
  384.     BMoveToStart();
  385.     }
  386.  
  387.  
  388. /* ------------------------------------------------------------ */
  389.  
  390. /* Bring the month into the range 1-12 and adjust the year
  391. accordingly. */
  392.  
  393. void
  394. D_MakeConsistent(yearptr, monptr)
  395.     int *yearptr;
  396.     int *monptr;
  397.     {
  398.     while (*monptr > 11) {
  399.         (*monptr) -= 12;
  400.         (*yearptr)++;
  401.         }
  402.     while (*monptr < 0) {
  403.         (*monptr) += 12;
  404.         (*yearptr)--;
  405.         }
  406.     if (*yearptr > 9999) {
  407.         *monptr = 11;
  408.         *yearptr = 9999;
  409.         }
  410.     if (*yearptr < 1583) {
  411.         *monptr = 0;
  412.         *yearptr = 1583;
  413.         }
  414.     }
  415.  
  416.  
  417. /* end of DATE.C -- Calendar Routines */
  418.